/*
 * Copyright (C) 2025 ameise <ameise.wang@gmail.com> - All Rights Reserved
 *
 * This file is part of e3ds.
 *
 * e3ds is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * e3ds is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with e3ds. If not, see <https://www.gnu.org/licenses/>.
 */

package deque

import "sync"

var listQueueElementPool sync.Pool

func init() {
	listQueueElementPool = sync.Pool{New: func() any {
		return &Element{}
	}}
}

type Element struct {
	value any
	prev  *Element
	next  *Element
}

func NewList[T any]() *List[T] {
	n := listQueueElementPool.Get().(*Element)
	n.prev = nil
	n.next = nil
	return &List[T]{head: n, tail: n}
}

type List[T any] struct {
	head *Element
	tail *Element
	zero T
	size int
}

func (ts *List[T]) ResetCap(int) (int, error) {
	panic("list queue can not reset capacity")
}

func (ts *List[T]) IsEmpty() bool {
	return ts.size == 0
}

func (ts *List[T]) Size() int {
	return ts.size
}

func (ts *List[T]) PushFront(v T) error {
	newHead := listQueueElementPool.Get().(*Element)
	newHead.value = v

	newHead.next = ts.head
	ts.head.prev = newHead

	ts.head = newHead
	ts.size++
	return nil
}

func (ts *List[T]) PushFrontBatch(vs []T) error {
	for _, v := range vs {
		_ = ts.PushFront(v)
	}
	return nil
}

func (ts *List[T]) PushBack(v T) error {
	newTail := listQueueElementPool.Get().(*Element)
	ts.tail.value = v

	newTail.prev = ts.tail
	ts.tail.next = newTail

	ts.tail = newTail
	ts.size++
	return nil
}

func (ts *List[T]) PushBackBatch(vs []T) error {
	for _, v := range vs {
		_ = ts.PushBack(v)
	}
	return nil
}

func (ts *List[T]) PopFront() (T, error) {
	if ts.head == ts.tail {
		return ts.zero, ErrEmpty
	}
	return ts.popFront(), nil
}

func (ts *List[T]) PopFrontBatch(n int) ([]T, error) {
	if ts.head == ts.tail {
		return nil, ErrEmpty
	}
	if ts.size < n {
		return nil, ErrShort
	}
	out := make([]T, 0, n)
	for i := 0; i < n; i++ {
		out = append(out, ts.popFront())
	}
	return out, nil
}

func (ts *List[T]) PopFrontHalf() ([]T, error) {
	n := ts.size / 2
	if n == 0 {
		return nil, ErrShort
	}
	return ts.PopFrontBatch(n)
}

func (ts *List[T]) PopFrontAll() ([]T, error) {
	if ts.head == ts.tail {
		return nil, ErrEmpty
	}

	out := make([]T, 0, ts.size)

	for ts.size > 0 {
		out = append(out, ts.popFront())
	}
	return out, nil
}

func (ts *List[T]) PopBack() (T, error) {
	if ts.head == ts.tail {
		return ts.zero, ErrEmpty
	}
	return ts.popBack(), nil
}

func (ts *List[T]) PopBackBatch(n int) ([]T, error) {
	if ts.head == ts.tail {
		return nil, ErrEmpty
	}
	if ts.size < n {
		return nil, ErrShort
	}
	out := make([]T, 0, n)
	for i := 0; i < n; i++ {
		out = append(out, ts.popBack())
	}
	return out, nil
}

func (ts *List[T]) PopBackHalf() ([]T, error) {
	n := ts.size / 2
	if n == 0 {
		return nil, ErrShort
	}
	return ts.PopBackBatch(n)
}
func (ts *List[T]) PopBackAll() ([]T, error) {
	if ts.head == ts.tail {
		return nil, ErrEmpty
	}

	out := make([]T, 0, ts.size)
	for ts.size > 0 {
		out = append(out, ts.popBack())
	}
	return out, nil
}

func (ts *List[T]) Enqueue(v T) error {
	return ts.PushFront(v)
}

func (ts *List[T]) EnqueueBatch(vs []T) error {
	return ts.PushFrontBatch(vs)
}

func (ts *List[T]) Peek() (T, error) {
	if ts.head == ts.tail {
		return ts.zero, ErrEmpty
	}
	return ts.tail.prev.value.(T), nil
}

func (ts *List[T]) Dequeue() (T, error) {
	return ts.PopBack()
}

func (ts *List[T]) DequeueBatch(n int) ([]T, error) {
	return ts.PopBackBatch(n)
}

func (ts *List[T]) DequeueHalf() ([]T, error) {
	return ts.PopBackHalf()
}

func (ts *List[T]) DequeueAll() ([]T, error) {
	return ts.PopBackAll()
}

func (ts *List[T]) Push(t T) error {
	return ts.PushBack(t)
}

func (ts *List[T]) PushBatch(t []T) error {
	return ts.PushBackBatch(t)
}

func (ts *List[T]) Pop() (T, error) {
	return ts.PopBack()
}

func (ts *List[T]) PopBatch(n int) ([]T, error) {
	return ts.PopBackBatch(n)
}

func (ts *List[T]) PopHalf() ([]T, error) {
	return ts.PopBackHalf()
}

func (ts *List[T]) PopAll() ([]T, error) {
	return ts.PopBackAll()
}

// 内部辅助方法
func (ts *List[T]) popFront() T {
	nd := ts.head
	v := nd.value

	ts.head = nd.next

	nd.value = nil
	nd.next = nil
	listQueueElementPool.Put(nd)
	ts.size--
	return v.(T)
}

func (ts *List[T]) popBack() T {
	nd := ts.tail.prev
	v := nd.value

	ts.tail.prev = nd.prev
	if nd == ts.head {
		ts.head = ts.tail
	} else {
		nd.prev.next = ts.tail
	}

	nd.value = nil
	nd.prev = nil
	nd.next = nil
	listQueueElementPool.Put(nd)

	ts.size--
	return v.(T)
}
